package com.starryx.sim.mvc.net;


import com.starryx.sim.mvc.config.ServerConfig;
import com.starryx.sim.mvc.lifecycle.Lifecycle;
import com.starryx.sim.mvc.lifecycle.Priority;
import com.starryx.sim.mvc.net.handler.HttpServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicBoolean;


@Component
@Priority(1)
public class HttpServer implements Lifecycle {

	private static final Logger log = LogManager.getLogger(HttpServer.class);

	@Autowired
	private ServerConfig serverConfig;

	private EventLoopGroup bossGroup;

	private EventLoopGroup workerGroup;

	private AtomicBoolean isRunning = new AtomicBoolean(false);

	@Override
	public void init() {
		this.bossGroup = new NioEventLoopGroup(serverConfig.getBossGroupThread());
		this.workerGroup = new NioEventLoopGroup(serverConfig.getWorkerGroupThread());
		start();
		log.info("服务端启动成功，ip：{}，端口：{}", this.serverConfig.getIp(), this.serverConfig.getPort());
	}

	@Override
	public void destroy() throws Throwable {
		shutdown();
	}

	private void start() {
		if (!this.isRunning.compareAndSet(false, true)) {
			log.info("Server 已经启动");
		} else {
			try {
				ServerBootstrap bootstrap = new ServerBootstrap();
				bootstrap.group(this.bossGroup, this.workerGroup).channel(NioServerSocketChannel.class).childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true)
						.option(ChannelOption.SO_BACKLOG, 128).childHandler(new ChannelInitializer<SocketChannel>() {
					@Override
					protected void initChannel(SocketChannel socketChannel) throws Exception {
						ChannelPipeline channelPipeline = socketChannel.pipeline();
						channelPipeline.addLast("decoder", new HttpRequestDecoder()).addLast("encoder", new HttpResponseEncoder()).addLast("aggregator", new HttpObjectAggregator(512 * 1024))
								.addLast("handler", new HttpServerHandler());
					}
				});
				bootstrap.bind(this.serverConfig.getIp(), this.serverConfig.getPort()).sync();
			} catch (Exception e) {
				this.shutdown();
				log.info("绑定地址失败：{}:{}", this.serverConfig.getIp(), this.serverConfig.getPort());
			}
		}
	}

	private void shutdown() {
		if (!this.isRunning.compareAndSet(true, false)) {
			log.info("Server 已经关闭");
		}

		try {
			this.bossGroup.shutdownGracefully().sync();
			this.workerGroup.shutdownGracefully().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public boolean isRunning() {
		return this.isRunning.get();
	}

	public ServerConfig getServerConfig() {
		return this.serverConfig;
	}

}
